package com.wall.haven.filter;

import com.baomidou.mybatisplus.extension.api.R;
import com.wall.haven.config.SystemConfigCache;
import com.wall.haven.enums.ResultCode;
import com.wall.haven.exception.ExpireSecretException;
import com.wall.haven.exception.ExpireTokenException;
import com.wall.haven.exception.IllegalTokenException;
import com.wall.haven.exception.handler.DefaultExceptionAdvice;
import com.wall.haven.util.RSAUtils;
import com.wall.haven.util.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 过滤器
 *
 * @author ChenWangKun
 * @date 2023-06-08
 **/

@Component("authenticationFilter")
public class AuthenticationFilter extends OncePerRequestFilter {

    /** logger */
    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationFilter.class);

    @Resource
    private SystemConfigCache systemConfigCache;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        LOGGER.debug("接收请求：" + request.getQueryString());
        try {
            this.auth(request);
        } catch (Exception e) {
            this.handlerException(request,response,e);
            return;
        }
        filterChain.doFilter(request, response);
    }

    /**
     * 检查请求合法性
     *
     * @param request
     * @return
     */
    private void auth(HttpServletRequest request) {
            String requestURI = request.getRequestURI();
            if (requestURI.startsWith("/proxy")){
                //获取请求头中的加密信息
                String token = request.getHeader(HttpHeaders.AUTHORIZATION);
                if (token == null) {
                    token = request.getParameter("t");
                }
                if (StringUtils.isEmpty(token)) {
                    throw new IllegalTokenException();
                }
                String decrypt = null;
                try {
                    decrypt = RSAUtils.decrypt(token, systemConfigCache.getRsaPrivateKey());
                } catch (Exception e) {
                    throw new IllegalTokenException(e);
                }
                String[] split = decrypt.split("\\|");
                String secretKey = split[0];
                long timestamp = Long.parseLong(split[1]);
                if (!systemConfigCache.getSecretKey().equals(secretKey)) {
                    throw new ExpireSecretException("授权码不正确");
                }
                //校验是否过期
                if (System.currentTimeMillis() - timestamp > systemConfigCache.getSecretValidTime()) {
                    throw new ExpireTokenException();
                }
            }
    }

    /**
     * 处理鉴权异常
     *
     * @param request
     * @param response
     * @param e        异常
     * @author ChenWangKun
     * @date 2023/6/20
     */
    private void handlerException(HttpServletRequest request, HttpServletResponse response, Exception e) throws IOException {
        //设置跨域
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "*");
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
        response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        R apiResult;
        if (e instanceof ExpireTokenException) {
            apiResult = DefaultExceptionAdvice.defHandler(ResultCode.EXPIRED_TOKEN, e, request);
        } else if (e instanceof ExpireSecretException) {
            apiResult = DefaultExceptionAdvice.defHandler(ResultCode.EXPIRED_SECRET, e, request);
        } else if (e instanceof IllegalTokenException) {
            apiResult = DefaultExceptionAdvice.defHandler(ResultCode.INVALID_TOKEN, e, request);
        } else {
            apiResult = DefaultExceptionAdvice.defHandler(ResultCode.AUTHENTICATION_FAILED, e, request);
        }
        ResponseUtil.result(response, apiResult);
    }
}
